using GEM.Domain.Entities;
using GEM.Domain.Repositories;
using GEM.Infrastructure.DB;
using Microsoft.EntityFrameworkCore;

namespace GEM.Infrastructure.Repositories;

public class FileRepository : IFileRepository
{
    private readonly AppDbContext _db;
    public FileRepository(AppDbContext db)
    {
        _db = db;
    }

    public async Task<FileItem> CreateAsync(FileItem entity)
    {
        var obj = (await _db.AddAsync(entity)).Entity;
        await _db.SaveChangesAsync();
        return obj;
    }

    public async Task DeleteAsync(FileItem entity)
    {
        entity.IsDeleted = true;
        await UpdateAsync(entity);
    }

    public async Task<IEnumerable<FileItem>> GetAllAsync()
    {
        return await _db.Set<FileItem>().AsNoTracking().ToListAsync();
    }

    public async Task<FileItem?> GetByIdAsync(Guid id)
    {
        return await _db.Set<FileItem>().FindAsync(id);
    }

    public async Task UpdateAsync(FileItem entity)
    {
        _db.Update(entity);
        await _db.SaveChangesAsync();
    }

    public async Task<IEnumerable<FileItem>> ListByOwnerIdAsync(Guid ownerId)
    {
        return await _db.Set<FileItem>().Where(f => f.OwnerId == ownerId && !f.IsDeleted).ToListAsync();
    }

    public async Task<FileItem?> FindByPathAsync(string filePath)
    {
        return await _db.Set<FileItem>().FirstOrDefaultAsync(f => f.FilePath == filePath && !f.IsDeleted);
    }

    public void Attach(FileItem entity)
    {
        _db.Attach(entity);
    }

    public async Task<(IEnumerable<FileItem> Items, int TotalCount)> GetPagedAsync(int pageIndex, int pageSize, params System.Linq.Expressions.Expression<Func<FileItem, object>>[] includes)
    {
        IQueryable<FileItem> query = _db.Set<FileItem>().AsNoTracking();
        foreach (var include in includes)
        {
            query = query.Include(include);
        }
        var total = await query.CountAsync();
        var items = await query.Skip((pageIndex - 1) * pageSize).Take(pageSize).ToListAsync();
        return (items, total);
    }

    public async Task<FileItem?> GetSingleWithIncludesAsync(System.Linq.Expressions.Expression<Func<FileItem, bool>> predicate, params System.Linq.Expressions.Expression<Func<FileItem, object>>[] includes)
    {
        IQueryable<FileItem> query = _db.Set<FileItem>();
        foreach (var include in includes)
        {
            query = query.Include(include);
        }
        return await query.FirstOrDefaultAsync(predicate);
    }

    public async Task<FileItem?> GetByIdWithIncludesAsync(Guid id, params System.Linq.Expressions.Expression<Func<FileItem, object>>[] includes)
    {
        IQueryable<FileItem> query = _db.Set<FileItem>();
        foreach (var include in includes)
        {
            query = query.Include(include);
        }
        return await query.FirstOrDefaultAsync(e => e.Id == id);
    }

    public async Task<int> DeleteAsync(Guid id)
    {
        var obj = await GetByIdAsync(id);
        if (obj == null)
        {
            return 0;
        }
        _db.Set<FileItem>().Remove(obj);
        await _db.SaveChangesAsync();
        return 1;
    }

    public Task<GEM.Domain.Entities.App.AppUser?> GetUserWithRolesAsync(Guid userId)
    {
        throw new NotImplementedException();
    }

    public Task<GEM.Domain.Entities.App.AppRole?> GetRoleWithUsersAsync(Guid roleId)
    {
        throw new NotImplementedException();
    }

    public Task<GEM.Domain.Entities.App.AppPermission?> GetPermissionWithRolesAsync(Guid roleId)
    {
        throw new NotImplementedException();
    }

    public Task<GEM.Domain.Entities.App.AppRole?> GetRoleWithPermissionsAsync(Guid roleId)
    {
        throw new NotImplementedException();
    }
}
